<?php
namespace app\frontend\middleware;

use app\frontend\ApiBaseController;
use app\frontend\library\JwtAuth;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Db;
use think\Model;
use think\Response;
use think\facade\Log;
use think\response\Json;

class JwtAuthMiddleware extends ApiBaseController
{
    /**
     * 验证Token
     * @param $request
     * @param \Closure $next
     * @return mixed|Json
     */
    public function handle($request, \Closure $next)
    {
        // 1. 获取并清理Token
        $token = $this->getTokenFromHeader($request);

        if (!$token) {
            return $this->unauthorized('Token missing');
        }

        // 2. 验证Token
        $userInfo = JwtAuth::verifyToken($token);

        // 3. 处理验证结果
        if ($userInfo === false) {
            return $this->unauthorized('Invalid token');
        }

        // 4. 处理Token过期情况
        if (isset($userInfo['error']) && $userInfo['error'] === 'token_expired') {
            return $this->handleTokenExpiration($request, $next, $token);
        }

        // 查询数据库，判断用户是否存在（后台禁用或删除），不存在则直接退出登录
        if(!$this->checkUserFromDb($userInfo['user_id'])) {
            return $this->forceUnauthorized('User not exist');
        }

        // 5. 注入用户信息
        $request->user = $userInfo;

        return $next($request);
    }

    /**
     * 从请求头中获取Token
     * @param $request
     * @return string|string[]|null
     */
    private function getTokenFromHeader($request)
    {
        $token = $request->header('Authorization', '');
        return preg_replace('/^Bearer\s+/i', '', $token);
    }

    /**
     * 处理Token过期（无感刷新机制）
     * @param $request
     * @param $next
     * @param $originalToken
     * @return mixed|Json
     */
    private function handleTokenExpiration($request, $next, $originalToken)
    {
        // 1. 获取Refresh Token
        $refreshToken = $request->cookie('refresh_token');

        if (empty($refreshToken)) {
            return $this->unauthorized('Token expired. No refresh token provided');
        }

        // 2. 验证Refresh Token
        $userId = JwtAuth::verifyRefreshToken($refreshToken);

        if (!$userId) {
            return $this->unauthorized('Invalid refresh token');
        }

        // 查询数据库，判断用户是否存在（后台禁用或删除），不存在则直接退出登录
        if(!$this->checkUserFromDb($userId)) {
            return $this->forceUnauthorized('User not exist');
        }

        // 3. 验证原始Token中的用户ID
        $originalUserId = JwtAuth::getUserIdFromToken($originalToken);

        if ($originalUserId !== $userId) {
            Log::warning("Token user mismatch: $originalUserId vs $userId");
            return $this->unauthorized('User mismatch between tokens');
        }

        // 4. 设置用户信息
        $request->user = ['user_id' => $userId];

        // 5. 继续处理请求
        $response = $next($request);

        // 6. 生成并返回新Access Token
        $newAccessToken = JwtAuth::createAccessToken($userId, config('set.jwt.expires_in', 1800));

        return $response->header([
            'New-Access-Token' => $newAccessToken,
        ]);
    }

    /**
     * 从数据库中检查账号是否存在（后台禁用或删除,立即退出登录）
     * @param $userId
     * @return array|mixed|Db|Model|null
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    private function checkUserFromDb($userId)
    {
        return Db::name('user')
            ->where(['id' => $userId])
            ->where('status', 1)
            ->find();
    }
}